package com.heu.blood.match.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heu.blood.analysis.dao.BloodTestTransfusionDao;
import com.heu.blood.analysis.entity.BloodTestTransfusionEntity;
import com.heu.blood.application.entity.BloodApplicationItemEntity;
import com.heu.blood.application.service.BloodApplicationItemService;
import com.heu.blood.application.vo.BloodApplicationVo;
import com.heu.blood.charge.dictenum.BloodChargeTypeEnum;
import com.heu.blood.charge.entity.BloodChargeEntity;
import com.heu.blood.charge.service.BloodChargeService;
import com.heu.blood.common.Constant.ConstantData;
import com.heu.blood.common.aop.ServiceLogAnnotation;
import com.heu.blood.common.commponent.DictionaryLoader;
import com.heu.blood.common.enums.BloodChargeEnum;
import com.heu.blood.common.enums.BloodStateEnum;
import com.heu.blood.common.utils.GenerateNumberBySnowFlake;
import com.heu.blood.common.utils.PageUtils;
import com.heu.blood.common.utils.Query;
import com.heu.blood.globalExceptionHandler.MyException;
import com.heu.blood.match.dao.BloodMatchDao;
import com.heu.blood.match.dictenum.BloodMatchStatusEnum;
import com.heu.blood.match.dictenum.MatchStateEnum;
import com.heu.blood.match.dictenum.TestResultEnum;
import com.heu.blood.match.dto.req.BloodTransfusionStateChangeReqDTO;
import com.heu.blood.match.dto.resp.MathchedPatientInformationRespDTO;
import com.heu.blood.match.dto.resp.SearchNewMatchBloodRespDTO;
import com.heu.blood.match.entity.BloodInformationEntity;
import com.heu.blood.match.entity.BloodMatchEntity;
import com.heu.blood.match.entity.PatientInformationEntity;
import com.heu.blood.match.exception.TestTranfusionException;
import com.heu.blood.match.exception.TimeException;
import com.heu.blood.match.service.BloodInformationService;
import com.heu.blood.match.service.BloodMatchService;
import com.heu.blood.match.service.PatientInformationService;
import com.heu.blood.match.vo.*;
import com.heu.blood.send.dao.BloodSendDao;
import com.heu.blood.send.entity.BloodSendEntity;
import com.heu.blood.transfusion.entity.TransfusionApplicationEntity;
import com.heu.blood.transfusion.service.TransfusionApplicationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.heu.blood.common.enums.BloodInformationEnum.*;
import static com.heu.blood.common.enums.BloodMatchEnum.*;
import static com.heu.blood.common.enums.CommonEnum.IF_SHOW;


@Slf4j
@Service("bloodMatchService")
public class BloodMatchServiceImpl extends ServiceImpl<BloodMatchDao, BloodMatchEntity> implements BloodMatchService {

    @Autowired
    private TransfusionApplicationService transfusionApplicationService;

    @Autowired
    private BloodInformationService bloodInformationService;

    @Autowired
    private BloodMatchDao bloodMatchDao;

    @Autowired
    private BloodSendDao bloodSendDao;

    @Autowired
    private PatientInformationService patientInformationService;

    @Autowired
    BloodApplicationItemService bloodApplicationItemService;

    @Autowired
    private DictionaryLoader dictionaryLoader;

    @Autowired
    private BloodChargeService bloodChargeService;

    @Autowired
    private BloodTestTransfusionDao bloodTestTransfusionDao;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        // 构造bloodMatchEntity对象
        BloodMatchEntity bloodMatchEntity = new BloodMatchEntity();
        if (Strings.isNotBlank((String) params.get("transfusionId"))) {
            bloodMatchEntity.setApplicationId((String) params.get("transfusionId"));
        }
        if (Strings.isNotBlank((String) params.get("bloodId"))) {
            bloodMatchEntity.setBloodId((String) params.get("bloodId"));
        }
        if (Strings.isNotBlank((String) params.get("patientId"))) {
            bloodMatchEntity.setPatientId((String) params.get("patientId"));
        }
        if (Strings.isNotBlank((String) params.get("matchId"))) {
            bloodMatchEntity.setMatchId((String) params.get("matchId"));
        }
        if (Strings.isNotBlank((String) params.get("approvalStatus"))){
            bloodMatchEntity.setApprovalStatus((String) params.get("approvalStatus"));
        }

        // 构造条件构造器
        LambdaQueryWrapper<BloodMatchEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加过滤条件
        queryWrapper.eq(Strings.isNotBlank(bloodMatchEntity.getApplicationId()), BloodMatchEntity::getApplicationId, bloodMatchEntity.getApplicationId())
                .eq(Strings.isNotBlank(bloodMatchEntity.getBloodId()), BloodMatchEntity::getBloodId, bloodMatchEntity.getBloodId())
                .eq(Strings.isNotBlank(bloodMatchEntity.getPatientId()), BloodMatchEntity::getPatientId, bloodMatchEntity.getPatientId())
                .eq(Strings.isNotBlank(bloodMatchEntity.getMatchId()), BloodMatchEntity::getMatchId, bloodMatchEntity.getMatchId())
                .eq(Strings.isNotBlank(bloodMatchEntity.getApprovalStatus()), BloodMatchEntity::getApprovalStatus, bloodMatchEntity.getApprovalStatus())
                .eq(BloodMatchEntity::getIfShow, IF_SHOW.code());
        IPage<BloodMatchEntity> page = this.page(
                new Query<BloodMatchEntity>().getPage(params),
                queryWrapper
        );


        return new PageUtils(page);
    }

    /**
     * 寻找符合条件血液进行配血
     *
     * @param transfusionId
     * @return
     */
    @Override
    public List<BloodInformationEntity> search(String transfusionId) {
        // 根据输血申请单号获取输血申请单信息
        TransfusionApplicationEntity transfusionApplicationEntity = transfusionApplicationService.queryByTransfusionId(transfusionId);
        if (transfusionApplicationEntity == null){
            // 没有该输血申请单信息
            return null;
        }
        // 添加查询条件
        BloodInformationEntity bloodInformation = new BloodInformationEntity();
        bloodInformation.setAboBloodType(transfusionApplicationEntity.getAboBloodType());
        bloodInformation.setRhBloodType(transfusionApplicationEntity.getRhBloodType());
        bloodInformation.setBloodType(transfusionApplicationEntity.getBloodType());
        bloodInformation.setBloodCount(transfusionApplicationEntity.getApplyCount());
        bloodInformation.setMeasurementUnit(transfusionApplicationEntity.getMeasurementUnit());
        bloodInformation.setFailureTime(transfusionApplicationEntity.getTransfusionTime());

        // 返回符合条件的配血信息
        return bloodInformationService.searchMatchBlood(bloodInformation);
    }


    /**
     * 条件查询交叉配血表信息
     * @param bloodMatchEntity
     * @return
     */
    @Override
    public List<BloodMatchEntity> query(BloodMatchEntity bloodMatchEntity) {
        // 构造queryWrapper对象
        LambdaQueryWrapper<BloodMatchEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加过滤条件
        queryWrapper.eq(Strings.isNotBlank(bloodMatchEntity.getApplicationId()), BloodMatchEntity::getApplicationId, bloodMatchEntity.getApplicationId())
                    .eq(Strings.isNotBlank(bloodMatchEntity.getBloodId()), BloodMatchEntity::getBloodId, bloodMatchEntity.getBloodId())
                    .eq(Strings.isNotBlank(bloodMatchEntity.getPatientId()), BloodMatchEntity::getPatientId, bloodMatchEntity.getPatientId())
                    .eq(Strings.isNotBlank(bloodMatchEntity.getMatchId()), BloodMatchEntity::getMatchId, bloodMatchEntity.getMatchId())
                    .eq(Strings.isNotBlank(bloodMatchEntity.getBloodTypePatient()),BloodMatchEntity::getBloodTypePatient, bloodMatchEntity.getBloodTypePatient())
                    .eq(Strings.isNotBlank(bloodMatchEntity.getApprovalStatus()), BloodMatchEntity::getApprovalStatus, bloodMatchEntity.getApprovalStatus())
                    .eq(BloodMatchEntity::getIfShow, IF_SHOW.code());
        // 筛选出符合条件的配血记录并返回
        return bloodMatchDao.selectList(queryWrapper);
    }

    /**
     * 根据配血单号查询配血记录表
     * @param matchId
     * @return
     */
    @Override
    public BloodMatchEntity queryByMatchId(String matchId) {
        // 构造queryWrapper对象
        LambdaQueryWrapper<BloodMatchEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加过滤条件
        queryWrapper.eq(Strings.isNotBlank(matchId), BloodMatchEntity::getMatchId, matchId)
                    .eq(BloodMatchEntity::getIfShow, IF_SHOW.code());
        // 筛选出符合条件的配血记录并返回
        return bloodMatchDao.selectOne(queryWrapper);
    }

    /**
     * 判定交叉配血是否成功
     * @param matchId
     * @return
     */
    @Override
    @Transactional // 加上事务，因为要更新两个状态，一个配血表状态，一个血液信息表状态
    public Pair<Boolean, String> verify(String matchId) {
        BloodMatchEntity bloodMatchEntity = this.queryByMatchId(matchId);
        String mainSideResult = bloodMatchEntity.getMainSideResult();
        String primarySideResult = bloodMatchEntity.getPrimarySideResult();
        String verifyResult;
        boolean reasonOption = true;
        // 之后需要更改为字典
        if (mainSideResult.equals(MAIN_SIDE_PASS.code()) && primarySideResult.equals(MAIN_SIDE_PASS.code())){
            verifyResult = VERIFY_PASS.code();
            // 通过后也需要更改相应血液状态
            BloodInformationEntity bloodInformation = bloodInformationService.queryByBloodId(bloodMatchEntity.getBloodId()); // 先找到对应的血液信息
            bloodInformation.setBloodState(BLOOD_MATCH_SUCCESSED.code());
            bloodInformationService.updateById(bloodInformation);
        } else {
            // 不通过无非三种情况，主测结果不通过，次测结果不通过，主测次测结果都不通过
            if (!mainSideResult.equals(MAIN_SIDE_PASS.code())){
                if (primarySideResult.equals(MAIN_SIDE_PASS.code())){
                    // 主测结果不通过，次测结果通过
                    verifyResult = VERIFY_MAIN_FAIL.code();
                    reasonOption = false;
                    // 不通过后也需要更改相应血液状态
                    BloodInformationEntity bloodInformation = bloodInformationService.queryByBloodId(bloodMatchEntity.getBloodId()); // 先找到对应的血液信息
                    bloodInformation.setBloodState(BLOOD_MATCH_FAILED.code());
                    bloodInformationService.updateById(bloodInformation);
                }
                else {
                    // 主测次测都不通过
                    verifyResult = VERIFY_MAIN_FAIL.code();
                    reasonOption = false;
                    // 不通过后也需要更改相应血液状态
                    BloodInformationEntity bloodInformation = bloodInformationService.queryByBloodId(bloodMatchEntity.getBloodId()); // 先找到对应的血液信息
                    bloodInformation.setBloodState(BLOOD_MATCH_FAILED.code());
                    bloodInformationService.updateById(bloodInformation);
                }
            } else {
                // 主测结果通过，次测结果不通过
                verifyResult = VERIFY_PASS.code();
                reasonOption = false;
                // 不通过后也需要更改相应血液状态
                BloodInformationEntity bloodInformation = bloodInformationService.queryByBloodId(bloodMatchEntity.getBloodId()); // 先找到对应的血液信息
                bloodInformation.setBloodState(BLOOD_MATCH_FAILED.code());
                bloodInformationService.updateById(bloodInformation);
            }
        }
        // 保存verifyResult给bloodMatchEntity
        if (verifyResult.equals(VERIFY_PASS.code())){
            bloodMatchEntity.setBloodMatchStatus(BLOOD_MATCH_SUCCESS.code());
        } else {
            bloodMatchEntity.setBloodMatchStatus( BLOOD_MATCH_FAIL.code());
        }
        bloodMatchEntity.setState(verifyResult);
        // 更新这条记录
        this.updateById(bloodMatchEntity);
        // 返回结果
        return Pair.of(reasonOption, verifyResult);
    }

    /**
     * 通过患者id来寻找所有配血成功的血液
     * @param patientId
     * @return
     */
    @Override
    public List<BloodMatchEntity> searchMatchedBlood(String patientId) {
        // 1、先通过患者id找到对应的配血记录
        List<BloodMatchEntity> bloodMatchEntities = this.getByPatientId(patientId);
        // 2、遍历所有配血记录，并且state是PASS（配血通过）的配血记录
        List<BloodMatchEntity> filteredBloodMatches = bloodMatchEntities.stream()
                .filter(bloodMatchEntity -> Objects.equals(bloodMatchEntity.getState(), "PASS"))
                .filter(bloodMatchEntity -> bloodMatchEntity.getIfShow().toString().equals(IF_SHOW.code()))
                .collect(Collectors.toList());
        // 返回匹配的配血成功记录BloodMatchEntity
        return filteredBloodMatches;
    }

    /**
     * 根据患者id来查询患者配血表记录
     * @param patientId
     * @return
     */
    @Override
    public List<BloodMatchEntity> getByPatientId(String patientId) {
        // 创建lambdaQueryWrapper对象
        LambdaQueryWrapper<BloodMatchEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加查询条件
        queryWrapper.eq(Strings.isNotBlank(patientId), BloodMatchEntity::getPatientId, patientId)
                    .eq(BloodMatchEntity::getIfShow, IF_SHOW.code());
        // 返回查询结果
        return bloodMatchDao.selectList(queryWrapper);
    }

    @Override
    @Transactional
    public boolean changeBloodTransfusionState(BloodTransfusionStateChangeReqDTO requestParam) {
        boolean bloodFlag = bloodInformationService.updateBloodStateByBloodId(requestParam.getBloodId(), requestParam.getBloodState());
        boolean transfusionFlag = transfusionApplicationService.updateTransfusionStateByTransfusionId(requestParam.getTransfusionId(), requestParam.getTransfusionState());
        return bloodFlag && transfusionFlag;
    }

    @Override
    public List<BloodMatchEntity> searchBloodMathByBloodId(String bloodId) {
        LambdaQueryWrapper<BloodMatchEntity> queryWrapper = Wrappers.lambdaQuery(BloodMatchEntity.class)
                .eq(Strings.isNotBlank(bloodId), BloodMatchEntity::getBloodId, bloodId);
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public List<MathchedPatientInformationRespDTO> searchMatchedPatientInformation(String bloodId) {
        // 1、先根据血液id找到所有的配血记录
        List<BloodMatchEntity> bloodMatchList = searchBloodMathByBloodId(bloodId);
        List<MathchedPatientInformationRespDTO> mathchedPatientInformationRespDTOS = new ArrayList<>();
        // 2、根据patientId查询患者信息
        for(BloodMatchEntity bloodMatch : bloodMatchList){
           String patientId = bloodMatch.getPatientId();
           PatientInformationEntity patientInformation =  patientInformationService.queryWithPatientId(patientId);
           MathchedPatientInformationRespDTO mathchedPatientInformationRespDTO = MathchedPatientInformationRespDTO.builder()
                   .patientId(patientInformation.getPatientId())
                   .patientName(patientInformation.getPatientName())
                   .patientType(patientInformation.getPatientType())
                   .matchTime(bloodMatch.getMatchTime())
                   .matchPeople(bloodMatch.getMatchPeople())
                   .bloodMatchStatus(bloodMatch.getBloodMatchStatus())
                   .build();
           mathchedPatientInformationRespDTOS.add(mathchedPatientInformationRespDTO);
        }
        return mathchedPatientInformationRespDTOS;
    }

    @Override
    @ServiceLogAnnotation(module = "交叉配血", operate = "查找已经配成功并且没有发血的血液")
    public List<BloodMatchEntity> searchSuccessMatched(String transfusionId) {
        // 找到输血申请单号已经配成功的
        LambdaQueryWrapper<BloodMatchEntity> queryWrapper = Wrappers.lambdaQuery(BloodMatchEntity.class)
                .eq(Strings.isNotBlank(transfusionId), BloodMatchEntity::getApplicationId, transfusionId)
                .eq(BloodMatchEntity::getBloodMatchStatus, BLOOD_MATCH_SUCCESS.code());
        List<BloodMatchEntity> bloodMatchEntities = baseMapper.selectList(queryWrapper);
        // 剔除已经发血的
        List<BloodMatchEntity> bloodMatchEntitiesNoSend = bloodMatchEntities.stream()
                .filter(bloodMatch -> {
                    BloodInformationEntity usedBlood = bloodInformationService.queryByBloodId(bloodMatch.getBloodId());
                    return !usedBlood.getBloodState().equals(BLOOD_USED.code());
                })
                .peek(usedBlood -> log.info(usedBlood.toString()))
                .collect(Collectors.toList());
        return bloodMatchEntitiesNoSend;
    }

    /**
     * 去重查询符合条件的血液信息
     * @param requestParam
     * @return
     */
    @Override
    public List<BloodInformationEntity> searchBlood(SearchNewMatchBloodRespDTO requestParam) {
        // 配血失败有两种情况，1、一份血液一次或多次配血失败。2、一份申请单多种不同的血液成分配血失败（手术备血可能是一份申请单对应多份血液，常规备血是一对一）
        // 可以用transfusionId和bloodTypePatient来唯一确定一份配血失败的记录

        // 1、构造查询条件的bloodMatch
        BloodMatchEntity bloodMatchQuery = new BloodMatchEntity();
        bloodMatchQuery.setApplicationId(requestParam.getTransfusionId());
        bloodMatchQuery.setPatientId(requestParam.getPatientId());

        // 2、查询出所有符合条件的bloodMatch
        List<BloodMatchEntity> bloodMatchEntities = this.query(bloodMatchQuery);

        // 3、将配血失败的bloodId统一起来
        List<String> bloodIds = bloodMatchEntities.stream().map(BloodMatchEntity::getBloodId).collect(Collectors.toList());


        // 4、再根据输血申请单信息重新寻找一遍
        // 根据输血申请单号获取输血申请单信息
        List<BloodInformationEntity> bloodInformationEntities = this.search(requestParam.getTransfusionId());
        if (bloodInformationEntities == null || bloodInformationEntities.size() == 0){
            return bloodInformationEntities;
        }

        // 5、将配血失败的血液信息剔除出去
        List<BloodInformationEntity> validBloodInformationEntities = new ArrayList<>();
        for (BloodInformationEntity bloodInformationEntity : bloodInformationEntities) {
            if (!bloodIds.contains(bloodInformationEntity.getBloodId())) {
                validBloodInformationEntities.add(bloodInformationEntity);
            }
        }
        // 6、返回符合条件的血液信息
        return validBloodInformationEntities;
    }

    /**
    * @description: 该功能为患者维度的历史的配血记录进行查询
    * @param bloodMatchRecordQueryPatientDimensionVo
    * @return com.heu.blood.common.utils.PageUtils
    * @author lhh
    * @date 2024-07-17
    */

    @Override
    public PageUtils getBloodMatchRecordQueryPatientDimension(BloodMatchRecordQueryPatientDimensionVo bloodMatchRecordQueryPatientDimensionVo) {
//        查询献血码
        if (Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getBloodDonationCode())) {
            QueryWrapper<BloodMatchRecordQueryPatientDimensionVo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq(Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getBloodDonationCode()), "bi.blood_donation_code",
                    bloodMatchRecordQueryPatientDimensionVo.getBloodDonationCode())
                    .ge(Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getStartTime()), "bm.match_time",
                            bloodMatchRecordQueryPatientDimensionVo.getStartTime())
                    .le(Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getEndTime()), "bm.match_time",
                            bloodMatchRecordQueryPatientDimensionVo.getEndTime());
            Map<String, Object> params = new HashMap<>();
            if (Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getLimit())){
                params.put("limit", bloodMatchRecordQueryPatientDimensionVo.getLimit());
            }
            if (Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getPage())){
                params.put("page", bloodMatchRecordQueryPatientDimensionVo.getPage());
            }
            IPage<BloodMatchRecordQueryPatientDimensionVo> page = bloodMatchDao.selectBloodMatchRecordQueryPatientDimensionPageByDonationCode(
                    new Query<BloodMatchRecordQueryPatientDimensionVo>().getPage(params),
                    queryWrapper
            );

            return new PageUtils(page);
        } else { // 不查询献血码的
            QueryWrapper<BloodMatchRecordQueryPatientDimensionVo> queryWrapper = new QueryWrapper<>();
            String startTime = bloodMatchRecordQueryPatientDimensionVo.getStartTime();
            String endTime = bloodMatchRecordQueryPatientDimensionVo.getEndTime();

            if (Strings.isNotBlank(startTime) && Strings.isNotBlank(endTime)) {
                if (startTime.compareTo(endTime) > 0) {
                    throw new MyException(TimeException.TIME_OUTLINE);
                }
            }
            queryWrapper.like(Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getPatientId()), "pi.patient_id",
                    bloodMatchRecordQueryPatientDimensionVo.getPatientId())
                    .like(Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getPatientName()), "pi.patient_name",
                            bloodMatchRecordQueryPatientDimensionVo.getPatientName())
                    .like(Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getBloodSampleInfoTransfusionId()), "bm.blood_sample_info_transfusion_id",
                            bloodMatchRecordQueryPatientDimensionVo.getBloodSampleInfoTransfusionId())
                    .ge(Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getStartTime()), "bm.match_time",
                            bloodMatchRecordQueryPatientDimensionVo.getStartTime())
                    .le(Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getEndTime()), "bm.match_time",
                            bloodMatchRecordQueryPatientDimensionVo.getEndTime());
            Map<String, Object> params = new HashMap<>();

            if (Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getLimit())){
                params.put("limit", bloodMatchRecordQueryPatientDimensionVo.getLimit());
            }
            if (Strings.isNotBlank(bloodMatchRecordQueryPatientDimensionVo.getPage())){
                params.put("page", bloodMatchRecordQueryPatientDimensionVo.getPage());
            }

            IPage<BloodMatchRecordQueryPatientDimensionVo> page = bloodMatchDao.selectBloodMatchRecordQueryPatientDimensionPage(
                    new Query<BloodMatchRecordQueryPatientDimensionVo>().getPage(params),
                    queryWrapper
            );

            return new PageUtils(page);

        }

    }

    /**
    * @description: 该功能为血袋维度的历史的配血记录进行查询
    * @param bloodMatchRecordQueryBagDimensionVo
    * @return com.heu.blood.common.utils.PageUtils
    * @author lhh
    * @date 2024-07-17
    */

    @Override
    public PageUtils getBloodMatchRecordQueryBagDimension(BloodMatchRecordQueryBagDimensionVo bloodMatchRecordQueryBagDimensionVo) {
        LambdaQueryWrapper<BloodInformationEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Strings.isNotBlank(bloodMatchRecordQueryBagDimensionVo.getBloodDonationCode()), BloodInformationEntity::getBloodDonationCode,
                bloodMatchRecordQueryBagDimensionVo.getBloodDonationCode())
                .eq(Strings.isNotBlank(bloodMatchRecordQueryBagDimensionVo.getBloodState()), BloodInformationEntity::getBloodState,
                        bloodMatchRecordQueryBagDimensionVo.getBloodState())
                .ge(Strings.isNotBlank(bloodMatchRecordQueryBagDimensionVo.getStartTime()), BloodInformationEntity::getMatchTime,
                        bloodMatchRecordQueryBagDimensionVo.getStartTime())
                .le(Strings.isNotBlank(bloodMatchRecordQueryBagDimensionVo.getEndTime()), BloodInformationEntity::getMatchTime,
                        bloodMatchRecordQueryBagDimensionVo.getEndTime())
                .eq(BloodInformationEntity::getIfShow, IF_SHOW.code());


        Map<String, Object> params = new HashMap<>();
        if (Strings.isNotBlank(bloodMatchRecordQueryBagDimensionVo.getLimit())){
            params.put("limit", bloodMatchRecordQueryBagDimensionVo.getLimit());
        }
        if (Strings.isNotBlank(bloodMatchRecordQueryBagDimensionVo.getPage())){
            params.put("page", bloodMatchRecordQueryBagDimensionVo.getPage());
        }

        queryWrapper.orderByDesc(BloodInformationEntity::getGmtCreate);
        IPage<BloodInformationEntity> page = bloodInformationService.page(
                new Query<BloodInformationEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils getBloodMatchRecordQueryBagDimensionByStatus(BloodMatchRecordQueryBagDimensionVo bloodMatchRecordQueryBagDimensionVo) {
        LambdaQueryWrapper<BloodInformationEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Strings.isNotBlank(bloodMatchRecordQueryBagDimensionVo.getBloodDonationCode()), BloodInformationEntity::getBloodDonationCode,
                bloodMatchRecordQueryBagDimensionVo.getBloodDonationCode())
                .in(BloodInformationEntity::getBloodState, Arrays.asList(BloodStateEnum.IN_MATCH.code(), BloodStateEnum.BLOOD_SEND.code()))
                .ge(Strings.isNotBlank(bloodMatchRecordQueryBagDimensionVo.getStartTime()), BloodInformationEntity::getMatchTime,
                        bloodMatchRecordQueryBagDimensionVo.getStartTime())
                .le(Strings.isNotBlank(bloodMatchRecordQueryBagDimensionVo.getEndTime()), BloodInformationEntity::getMatchTime,
                        bloodMatchRecordQueryBagDimensionVo.getEndTime())
                .eq(BloodInformationEntity::getIfShow, IF_SHOW.code());


        Map<String, Object> params = new HashMap<>();
        if (Strings.isNotBlank(bloodMatchRecordQueryBagDimensionVo.getLimit())){
            params.put("limit", bloodMatchRecordQueryBagDimensionVo.getLimit());
        }
        if (Strings.isNotBlank(bloodMatchRecordQueryBagDimensionVo.getPage())){
            params.put("page", bloodMatchRecordQueryBagDimensionVo.getPage());
        }

        queryWrapper.orderByDesc(BloodInformationEntity::getGmtCreate);
        IPage<BloodInformationEntity> page = bloodInformationService.page(
                new Query<BloodInformationEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    /**
     * 找到所有可以为当前申请单提供配血操作的血液
     * @param bloodApplicationVo
     */
    @Override
    public Map<Long,List<BloodInformationEntity>> getAllBloodCanUse(BloodApplicationVo bloodApplicationVo) {
        Map<Long,List<BloodInformationEntity>> res = new HashMap<>();
        List<BloodApplicationItemEntity> applicationItems = bloodApplicationVo.getApplicationItems();
        for(BloodApplicationItemEntity entity : applicationItems){
            Long id = entity.getId();
            /**
             * 1.获取血型相同
             * 2.获取abo和rh相同
             * 3.获取状态为在库或者是配血中
             * 4.获取量小于库存中的
             */
            LambdaQueryWrapper<BloodInformationEntity> infoWrapper = new LambdaQueryWrapper<>();
            infoWrapper.eq(Strings.isNotBlank(entity.getAboBloodType()),
                    BloodInformationEntity::getAboBloodType,entity.getAboBloodType())
                    .eq(Strings.isNotBlank(entity.getRhBloodType()),
                            BloodInformationEntity::getRhBloodType,entity.getRhBloodType())
                    .eq(Strings.isNotBlank(entity.getBloodType()),
                            BloodInformationEntity::getBloodType,entity.getBloodType())
                    .and(wq->wq.eq(BloodInformationEntity::getBloodState,BloodStateEnum.IN_STOCK.code()).or()
                            .eq(BloodInformationEntity::getBloodState,BloodStateEnum.IN_MATCH.code()))
//                    .ge(BloodInformationEntity::getBloodCount,entity.getApplyCount()); // 这个先不要管
                    .ge(BloodInformationEntity::getFailureTime,entity.getTransfusionTime());
            List<BloodInformationEntity> list = bloodInformationService.list(infoWrapper);
            // 查询出来
            LambdaQueryWrapper<BloodMatchEntity> matchWrapper = new LambdaQueryWrapper<>();
            matchWrapper.eq(Strings.isNotBlank(bloodApplicationVo.getApplicationId()),BloodMatchEntity::getApplicationId,
                    bloodApplicationVo.getApplicationId());
            List<BloodMatchEntity> bloodMatchEntities = bloodMatchDao.selectList(matchWrapper);
            List<BloodInformationEntity> finalList = new ArrayList<>();
            // 去重
            for(BloodInformationEntity bloodInfo : list){
                boolean flag = true;
                for(BloodMatchEntity bloodMatch : bloodMatchEntities){
                    if(bloodInfo.getBloodId().equals(bloodMatch.getBloodId())){
                        flag = false;
                        break;
                    }
                }
                if(flag){
                    finalList.add(bloodInfo);
                }
            }
            res.put(id,finalList);
        }
        return res;
    }

    /**
     * 进行交叉配血的插入
     * @param bloodMatchInsertVO
     * @return
     */
    @Override
    @Transactional
    public int insertBloodMatchInfo(BloodMatchInsertVO bloodMatchInsertVO) {
        // 雪花算法生成的配血id并保存到配血表中
        GenerateNumberBySnowFlake generateNumberBySnowFlake = new GenerateNumberBySnowFlake(ConstantData.BLOOD_MATCH_NO_PREFIX,ConstantData.BLOOD_MATCH_NO_WORK_ID);
        String matchId = generateNumberBySnowFlake.genNumberByflag();
        bloodMatchInsertVO.setBloodMatchStatus(BloodMatchStatusEnum.SUCCESS_MATCHED.code());
        bloodMatchInsertVO.setMatchId(matchId);
        this.save(bloodMatchInsertVO);

        // 在这里更新一下血液状态
        LambdaUpdateWrapper<BloodInformationEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Strings.isNotBlank(bloodMatchInsertVO.getBloodId()),BloodInformationEntity::getBloodState,
                BloodStateEnum.IN_MATCH.code())
                .eq(Strings.isNotBlank(bloodMatchInsertVO.getBloodId()),BloodInformationEntity::getBloodId,
                        bloodMatchInsertVO.getBloodId());
        bloodInformationService.update(updateWrapper);
        // 在这里更新一下申请单里面的申请项的状态
        BloodApplicationItemEntity item = new BloodApplicationItemEntity();
        item.setId(bloodMatchInsertVO.getBloodApplicationItemId());
        item.setMatchState(MatchStateEnum.MATCHED.code());
        bloodApplicationItemService.updateById(item);
        // 在这里增加一下收费项目非必须的方法
        BloodChargeEntity chargeEntityMain = new BloodChargeEntity();
        // 获取血袋的类型
        String matchMethod = bloodMatchInsertVO.getMatchMethod();
        Map<String, String> paymentProjectTranslate = dictionaryLoader.getPaymentProjectTranslate();
        String costMain = paymentProjectTranslate.get(matchMethod);
        chargeEntityMain.setUnitPrice(costMain);
        chargeEntityMain.setQuantity("1");
        chargeEntityMain.setTotalPrice(costMain);
        chargeEntityMain.setChargeState(BloodChargeEnum.CHARGE_UNVERIFIED.code());
        chargeEntityMain.setChargeType(BloodChargeTypeEnum.BLOOD_MATCHING_FEE.code());
        chargeEntityMain.setBloodId(bloodMatchInsertVO.getBloodId());
        chargeEntityMain.setPatientId(bloodMatchInsertVO.getPatientId());
        chargeEntityMain.setPatientName(bloodMatchInsertVO.getPatientName());
        chargeEntityMain.setApplicationId(bloodMatchInsertVO.getApplicationId());
        chargeEntityMain.setOperatorId(bloodMatchInsertVO.getMatchPeopleNumber());
        chargeEntityMain.setOperatorName(bloodMatchInsertVO.getMatchPeople());
        chargeEntityMain.setPayment(matchMethod);
        chargeEntityMain.setGender(bloodMatchInsertVO.getGender());
        chargeEntityMain.setApplyDepartment(bloodMatchInsertVO.getDepartment());
        chargeEntityMain.setDepartment(bloodMatchInsertVO.getDepartment());
        chargeEntityMain.setWard(bloodMatchInsertVO.getWard());
        chargeEntityMain.setBedNumber(bloodMatchInsertVO.getBedNumber());
        // 在这里增加一下收费项目必须的方法
        BloodChargeEntity chargeEntitySalt = new BloodChargeEntity();
        // 获取血袋的类型
        BeanUtils.copyProperties(chargeEntityMain,chargeEntitySalt);
        String matchMethodSalt = bloodMatchInsertVO.getMatchMethod();
        String costSalt = paymentProjectTranslate.get(matchMethodSalt);
        chargeEntitySalt.setUnitPrice(costSalt);
        chargeEntitySalt.setTotalPrice(costSalt);
        chargeEntitySalt.setPayment(matchMethodSalt);
        bloodChargeService.save(chargeEntityMain);
        bloodChargeService.save(chargeEntitySalt);
        return 0;
    }

    @Override
    public List<BloodMatchEntity> selectMatchListWithId(BloodMatchEntity bloodMatchEntity) {
        LambdaQueryWrapper<BloodMatchEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BloodMatchEntity::getBloodApplicationItemId,bloodMatchEntity.getBloodApplicationItemId());
        List<BloodMatchEntity> res = this.list(queryWrapper);
        return res;
    }

    @Override
    public List<BloodMatchWithBloodStateVo> selectMatchInfoWithBloodState(BloodMatchWithBloodStateVo bloodMatchEntity) {
        bloodMatchEntity.setBloodState(BloodStateEnum.IN_MATCH.code());
        return bloodMatchDao.selectMatchInfoWithBloodState(bloodMatchEntity);
    }

    @Override
    public List<BloodMatchEntity> selectMatchListWithApplicationItemId(Long bloodApplicationItemId) {
        LambdaQueryWrapper<BloodMatchEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BloodMatchEntity::getBloodApplicationItemId, bloodApplicationItemId);
        List<BloodMatchEntity> res = this.list(queryWrapper);
        return res;
    }

    @Override
    public List<BloodMatchEntity> getMatchListWithBloodIdAndApplicationItem(String bloodId, String bloodApplicationItemId) {
        LambdaQueryWrapper<BloodMatchEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BloodMatchEntity::getBloodApplicationItemId, Long.parseLong(bloodApplicationItemId))
        .eq(BloodMatchEntity::getBloodId, bloodId);
        List<BloodMatchEntity> res = bloodMatchDao.selectList(queryWrapper);
        return res;
    }

    @Override
    public BloodMatchAndSendVo getMatchAndSendInfo(BloodMatchEntity bloodMatchEntity) {
        // 先查询出来配血的信息
        LambdaQueryWrapper<BloodMatchEntity> matchQuery = new LambdaQueryWrapper<>();
        // 患者id相等
        matchQuery.eq(Strings.isNotBlank(bloodMatchEntity.getPatientId()),BloodMatchEntity::getPatientId,bloodMatchEntity.getPatientId());
        // 血袋编号
        matchQuery.eq(Strings.isNotBlank(bloodMatchEntity.getBloodId()),BloodMatchEntity::getBloodId,bloodMatchEntity.getBloodId());
        BloodMatchEntity bloodMatchInfo = bloodMatchDao.selectOne(matchQuery);


        // 先查询出来配血的信息
        LambdaQueryWrapper<BloodSendEntity> sendQuery = new LambdaQueryWrapper<>();
        // 患者id相等
        sendQuery.eq(Strings.isNotBlank(bloodMatchEntity.getPatientId()),BloodSendEntity::getPatientId,bloodMatchEntity.getPatientId());
        // 血袋编号
        sendQuery.eq(Strings.isNotBlank(bloodMatchEntity.getBloodId()),BloodSendEntity::getBloodId,bloodMatchEntity.getBloodId());
        BloodSendEntity bloodSendInfo = bloodSendDao.selectOne(sendQuery);

        BloodMatchAndSendVo res = new BloodMatchAndSendVo();
        res.setBloodMatchInfo(bloodMatchInfo);
        res.setBloodSendInfo(bloodSendInfo);
        return res;
    }

    @Override
    public List<BloodInformationEntity> getAllBloodCanUseNoMatch(BloodApplicationItemEntity bloodApplicationItemEntity) {
        /**
         * 1.获取血型相同
         * 2.获取abo和rh相同
         * 3.获取状态为在库或者是配血中
         * 4.获取量小于库存中的
         */
        LambdaQueryWrapper<BloodInformationEntity> infoWrapper = new LambdaQueryWrapper<>();
        infoWrapper.eq(Strings.isNotBlank(bloodApplicationItemEntity.getAboBloodType()),
                BloodInformationEntity::getAboBloodType,bloodApplicationItemEntity.getAboBloodType())
                .eq(Strings.isNotBlank(bloodApplicationItemEntity.getRhBloodType()),
                        BloodInformationEntity::getRhBloodType,bloodApplicationItemEntity.getRhBloodType())
                .eq(Strings.isNotBlank(bloodApplicationItemEntity.getBloodType()),
                        BloodInformationEntity::getBloodType,bloodApplicationItemEntity.getBloodType())
                .eq(BloodInformationEntity::getBloodState,BloodStateEnum.IN_STOCK.code())
//                    .ge(BloodInformationEntity::getBloodCount,entity.getApplyCount()); // 这个先不要管
                .ge(BloodInformationEntity::getFailureTime,bloodApplicationItemEntity.getTransfusionTime());
        List<BloodInformationEntity> res = bloodInformationService.list(infoWrapper);
        return res;
    }

    @Override
    public int checkBloodTestResult(String applicationId) {
        LambdaQueryWrapper<BloodTestTransfusionEntity> testTransfusionQuery = new LambdaQueryWrapper<>();
        testTransfusionQuery.eq(Strings.isNotBlank(applicationId), BloodTestTransfusionEntity::getApplicationId, applicationId);
        List<BloodTestTransfusionEntity> bloodTestTransfusionEntities = bloodTestTransfusionDao.selectList(testTransfusionQuery);

        if(bloodTestTransfusionEntities == null || bloodTestTransfusionEntities.isEmpty()) {
            throw new MyException(TestTranfusionException.TEST_FAILED);
        }

        for (BloodTestTransfusionEntity bloodTestTransfusion : bloodTestTransfusionEntities){
            String result = bloodTestTransfusion.getProjectResult();
            if (Strings.isBlank(result) || !result.equals(TestResultEnum.NORMAL.value())) {
                throw new MyException(TestTranfusionException.TEST_FAILED);
            }
        }
        return 0;
    }

    @Override
    public List<BloodMatchEntity> getMatchRecord(String patientId) {
        LambdaQueryWrapper<BloodMatchEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq( BloodMatchEntity::getPatientId, patientId);
        return bloodMatchDao.selectList(queryWrapper);
    }
}